package dag

import (
	"calculator/internal/core/expr"
	"calculator/internal/core/schema"
	"fmt"

	"github.com/pkg/errors"

	"gorm.io/gorm"
)

// DAGBuilder DAG依赖图构建器
type DAGBuilder struct {
	schemaInstance *schema.Schema // 模型实例
	dbInstance     *gorm.DB       // 数据库实例
}

// NewDAGBuilder 创建DAG构建器实例
func NewDAGBuilder(schema *schema.Schema, db *gorm.DB) *DAGBuilder {
	return &DAGBuilder{
		schemaInstance: schema,
		dbInstance:     db,
	}
}

// Build 根据Schema构建DAG依赖图
func (b *DAGBuilder) Build() (*DAG, error) {
	if b.schemaInstance == nil {
		return nil, errors.Errorf("DAGB001: Schema未初始化")
	}

	dag := NewDAG()

	// 为每个模型、表和字段创建节点并建立依赖
	if err := b.buildModelNodes(dag, b.schemaInstance); err != nil {
		return nil, err
	}

	// 验证DAG是否有环
	if dag.HasCycle() {
		return nil, errors.Errorf("DAGB002: 构建的DAG中存在环")
	}

	return dag, nil
}

// 构建模型相关节点
func (b *DAGBuilder) buildModelNodes(dag *DAG, schemaInstance *schema.Schema) error {
	for _, table := range schemaInstance.Tables {
		if err := b.buildTableNodes(dag, schemaInstance, &table); err != nil {
			return err
		}
	}
	return nil
}

// 构建表相关节点
func (b *DAGBuilder) buildTableNodes(dag *DAG, schemaInstance *schema.Schema, table *schema.Table) error {
	// 创建表节点
	tableNodeID := b.getTableNodeID(table.Name)
	tableNode := &Node{
		ID:        tableNodeID,
		FieldName: table.Name,
		TableName: table.Name,
	}
	if err := dag.AddNode(tableNode); err != nil {
		return errors.Wrapf(err, "DAGB003: 添加表节点失败: %s", tableNodeID)
	}

	// 为每个字段创建节点并建立依赖
	for _, field := range table.Fields {
		if err := b.buildFieldNode(dag, schemaInstance, table, &field); err != nil {
			return err
		}
	}

	return nil
}

// 构建字段节点并建立依赖
func (b *DAGBuilder) buildFieldNode(dag *DAG, schemaInstance *schema.Schema, table *schema.Table, field *schema.Field) error {
	// 创建字段节点
	fieldNodeID := b.getFieldNodeID(table.Name, field.Name)
	fieldNode := &Node{
		ID:        fieldNodeID,
		FieldName: field.Name,
		TableName: table.Name,
		Metadata: map[string]interface{}{
			"role": field.Role,
			"type": field.Type,
		},
	}
	if err := dag.AddNode(fieldNode); err != nil {
		return errors.Wrapf(err, "DAGB004: 添加字段节点失败: %s", fieldNodeID)
	}

	// 为公式字段建立依赖
	if field.Role == schema.RoleFormula {
		if err := b.buildFormulaDependencies(dag, schemaInstance, table, field, fieldNodeID); err != nil {
			return err
		}
	}

	return nil
}

// 为公式字段构建依赖关系
func (b *DAGBuilder) buildFormulaDependencies(dag *DAG, schemaInstance *schema.Schema, table *schema.Table, field *schema.Field, fieldNodeID string) error {
	// 优先处理ExprField，如果为空则处理DefaultExpr
	exprToAnalyze := ""
	if field.ExprField != "" {
		exprToAnalyze = field.ExprField
	} else if field.DefaultExpr != "" {
		exprToAnalyze = field.DefaultExpr
	} else {
		return nil
	}

	// 解析表达式并提取依赖
	// 创建表达式求值器
	evaluator := expr.NewEvaluator(b.dbInstance)
	evaluator.RegisterFunctions()
	evaluator.SetCurrentTable(table.Name)

	// 提取依赖关系，使用Schema进行自动表名推断
	dependencies, err := evaluator.ExtractDependencies(exprToAnalyze, schemaInstance)
	if err != nil {
		return errors.Wrapf(err, "DAGB006: 提取公式依赖失败: %s.%s, fieldName=%s, formula=%s", table.Name, field.Name, field.Name, exprToAnalyze)
	}

	// 添加解析出的依赖关系
	for _, dep := range dependencies {
		// 获取依赖字段的节点ID
		depFieldNodeID := b.getFieldNodeID(dep.TableName, dep.FieldName)

		// 检查依赖节点是否存在，不存在则创建
		if _, exists := dag.Nodes[depFieldNodeID]; !exists {
			// 查找依赖的表和字段
			depTable := b.findTable(schemaInstance, dep.TableName)
			if depTable == nil {
				return errors.Errorf("依赖的表不存在: tableName=%s, fieldName=%s, depTableName=%s", table.Name, field.Name, dep.TableName)
			}

			depField := b.findField(depTable, dep.FieldName)
			if depField == nil {
				return errors.Errorf("依赖的字段不存在: tableName=%s, fieldName=%s, depTableName=%s, depFieldName=%s", table.Name, field.Name, dep.TableName, dep.FieldName)
			}

			// 创建依赖字段节点
			depFieldNode := &Node{
				ID:        depFieldNodeID,
				FieldName: depField.Name,
				TableName: depTable.Name,
				Metadata: map[string]interface{}{
					"role": depField.Role,
					"type": depField.Type,
				},
			}
			if err := dag.AddNode(depFieldNode); err != nil {
				return errors.Wrapf(err, "DAGB009: 添加依赖字段节点失败: %s", depFieldNodeID)
			}
		}

		// 添加依赖边
		edge := &Edge{
			SourceID: depFieldNodeID,
			TargetID: fieldNodeID,
		}
		if err := dag.AddEdge(edge); err != nil {
			return errors.Wrapf(err, "DAGB010: 添加公式依赖边失败: source=%s, target=%s", depFieldNodeID, fieldNodeID)
		}
	}

	return nil
}

// 查找表
func (b *DAGBuilder) findTable(schemaInstance *schema.Schema, tableName string) *schema.Table {
	for _, t := range schemaInstance.Tables {
		if t.Name == tableName {
			return &t
		}
	}
	return nil
}

// 查找字段
func (b *DAGBuilder) findField(table *schema.Table, fieldName string) *schema.Field {
	for _, f := range table.Fields {
		if f.Name == fieldName {
			return &f
		}
	}
	return nil
}

// 获取表节点ID
func (b *DAGBuilder) getTableNodeID(tableName string) string {
	return fmt.Sprintf("table:%s", tableName)
}

// 获取字段节点ID
func (b *DAGBuilder) getFieldNodeID(tableName, fieldName string) string {
	return fmt.Sprintf("field:%s:%s", tableName, fieldName)
}
